﻿using UnityEngine;
using System.Collections;
using LitJson;
using System;


namespace NewEditorNS
{

    public enum EnumCameraState
    {
        normal, overshoulder
    }

    public class CameraCtrl : MonoBehaviour , IJsonData
    {
        public Func<bool> IsOnUICallback;
        public Func<bool> IsOnTextInput;

        bool isOnUI
        {
            get { return IsOnUICallback != null && IsOnUICallback(); }
        }

        bool isOnTextInput
        {
            get { return IsOnTextInput != null && IsOnTextInput(); }
        }


        public Vector3 OriVec = new Vector3();
        public float OriRotY = 45f;
        public float OriDis = 50f;
        public float OriSpeed = 100f;

        public bool CreateAvatar = true;

        Camera _tarCamera;
        public Camera tarCamera
        {
            get
            {
                if (_tarCamera == null)
                    _tarCamera = GetComponent<Camera>();
                return _tarCamera;
            }
        }

        private EnumCameraState _cameraState;

        public EnumCameraState CameraState
        {
            get { return _cameraState; }
            set
            {
                EnumCameraState oldState;
                oldState = _cameraState;
                _cameraState = value;
                switch (_cameraState)
                {
                    case EnumCameraState.normal:
                        TheFocusCtrl.RotV = 45f;
                        TheFocusCtrl.FocusDistance = 50f;
                        break;
                    case EnumCameraState.overshoulder:
                        TheFocusCtrl.RotV = -30;
                        TheFocusCtrl.FocusDistance = 3f;
                        break;
                }
            }
        }

        /// <summary>是否需要自行接受键盘事件并移动相机</summary>
        public bool needKeyboardCtrl = true;

        public FocusCtrl TheFocusCtrl = new FocusCtrl();

        private float moveSpeed = 100f;

        public float MoveSpeed
        {
            get { return moveSpeed; }
            set { moveSpeed = Mathf.Clamp(value, 1f, 10000f); }
        }

        void Awake()
        {
            //TheFocusCtrl
            TheFocusCtrl.createModel = CreateAvatar;

            
            TheFocusCtrl.FocusPos = OriVec;
            TheFocusCtrl.RotH = OriRotY;
            TheFocusCtrl.FocusDistance = OriDis;
            MoveSpeed = OriSpeed;
            CameraState = EnumCameraState.normal;
            TheFocusCtrl.refreshBiasPos();
        }

        void FixedUpdate()
        {
            if (CameraState == EnumCameraState.normal && !isOnUI)
                FocusDistanceCtrl();

            CameraRotate();

            if (needKeyboardCtrl && !isOnTextInput)
                CameraMove(SongeUtil.GetMoveInput(false));

            if (MonoHelper.Instance != null && MonoHelper.Instance.m_bShowMatView)
            {
                MatViewCtr();
            }
        }

        void LateUpdate()
        {
            TheFocusCtrl.refreshBiasPos();
            SetPosAndLookpoint();
        }

        void Update()
        {
            if (needKeyboardCtrl && ! isOnTextInput)
            {
                if (Input.GetKeyDown(KeyCode.Space))
                {
                    CameraState =
                        CameraState == EnumCameraState.normal ?
                        EnumCameraState.overshoulder : EnumCameraState.normal;
                }
            }
        }

        void SetPosAndLookpoint()
        {
            if (CameraState == EnumCameraState.overshoulder)
            {
                TheFocusCtrl.height = Mathf.Sin(45f / 180 * Mathf.PI) * TheFocusCtrl.FocusDistance;
                TheFocusCtrl.radius = Mathf.Cos(45f / 180 * Mathf.PI) * TheFocusCtrl.FocusDistance;
                float deltaX = TheFocusCtrl.radius * Mathf.Cos((180 - TheFocusCtrl.RotH) / 180 * Mathf.PI);
                float deltaY = TheFocusCtrl.radius * Mathf.Sin((180 - TheFocusCtrl.RotH) / 180 * Mathf.PI);
                TheFocusCtrl.DeltaVec.Set(deltaX, TheFocusCtrl.height, deltaY);
                tarCamera.transform.position = TheFocusCtrl.FocusPos + TheFocusCtrl.DeltaVec;
                float lookAtHeight = Mathf.Sin(TheFocusCtrl.RotV / 180 * Mathf.PI) * TheFocusCtrl.FocusDistance;
                Vector3 lookAt = TheFocusCtrl.FocusPos - new Vector3(0, lookAtHeight, 0);
                tarCamera.transform.LookAt(lookAt);
            }
            else if (CameraState == EnumCameraState.normal)
            {
                tarCamera.transform.position = TheFocusCtrl.FocusPos + TheFocusCtrl.DeltaVec;
                tarCamera.transform.LookAt(TheFocusCtrl.FocusPos);
            }
        }

        public void FocusDistanceCtrl()
        {
            if (isOnTextInput)
                return;
            float scroll = Input.GetAxis("Mouse ScrollWheel");
            float scrollDelta = 1 + TheFocusCtrl.FocusDistance * 0.1f;
            float scrollMulti = 0;
            if (scroll > 0)
                scrollMulti = -1;
            else if (scroll < 0)
                scrollMulti = 1;
            if (scrollMulti != 0)
                TheFocusCtrl.FocusDistance += scrollDelta * scrollMulti;
        }

        private void MatViewCtr()
        {
            float scroll = Input.GetAxis("Mouse ScrollWheel");
            float scrollDelta = 1 + TheFocusCtrl.FocusDistance * 0.1f;
            float scrollMulti = 0;
            if (scroll > 0)
                scrollMulti = -1;
            else if (scroll < 0)
                scrollMulti = 1;
            if (scrollMulti != 0)
                TheFocusCtrl.FocusDistance += scrollDelta * scrollMulti;
        }

        public void CameraMove(Vector3 moveInput)
        {
            float multi = 1;//
            switch (CameraState)
            {
                case EnumCameraState.normal:
                    multi = TheFocusCtrl.FocusDistance / 10f * MoveSpeed / 300f;
                    break;
                case EnumCameraState.overshoulder:
                    multi = TheFocusCtrl.FocusDistance / 10f * MoveSpeed / 300f * 5;
                    break;
                default:
                    multi = TheFocusCtrl.FocusDistance / 10f * MoveSpeed / 300f;
                    break;
            }
            Vector3 deltaMove = moveInput.GetScaledVector(multi);
            TheFocusCtrl.FocusPos += SongeUtil.MoveTowards((TheFocusCtrl.RotH) / 180 * Mathf.PI, deltaMove);
        }

        public void CameraRotate()
        {
            if (Input.GetMouseButton(1))
            {
                TheFocusCtrl.RotH += Input.GetAxis("Mouse X") * 2;
                TheFocusCtrl.RotV -= Input.GetAxis("Mouse Y") * 2;
            }
        }

        public JsonData ToJsonData()
        {
            JsonData jd = new JsonData();
            jd["focusPos"] = JsonUtils.vecToStr(TheFocusCtrl.FocusPos);
            jd["RotV"] = TheFocusCtrl.RotV;
            jd["RotH"] = TheFocusCtrl.RotH;
            jd["CameraState"] = CameraState.ToString();
            return jd;
        }

        public IJsonData ReadJsonData(JsonData jd)
        {
            TheFocusCtrl.FocusPos = JsonUtils.JsonToVec3(jd["focusPos"]);
            TheFocusCtrl.RotV = jd.ReadFloat("RotV");
            TheFocusCtrl.RotH = jd.ReadFloat("RotH");
            CameraState = jd.ReadEnum<EnumCameraState>("CameraState");
            return this;
        }
    }

    public class FocusCtrl
    {
        bool needRefreshBiasPos = false;
        public Vector3 DeltaVec;
        public float radius = 0;
        public float height = 0;
        public bool createModel = false;

        Animator _rollAnimator;
        Animator rollAnimator
        {
            get
            {
                if (_rollAnimator == null && focusBall != null)
                    _rollAnimator = focusBall.GetComponent<Animator>();
                return _rollAnimator;
            }
        }

        public GameObject focusBall;
        bool isWalk;
        public bool IsWalk
        {
            get { return isWalk; }
            set
            {
                isWalk = value;
                if (rollAnimator != null)
                    rollAnimator.SetBool("IsWalk", isWalk);
            }
        }

        private Vector3 focusPos;
        /// <summary>镜头焦点</summary>
        public Vector3 FocusPos
        {
            get { return focusPos; }
            set
            {
                Vector3 oldFocus = focusPos;
                IsWalk = oldFocus != value;

                focusPos = value;
                if (focusBall == null && createModel)
                {
                    focusBall = (GameObject)GameObject.Instantiate(Resources.Load("SongyiTest/RenWu/Prefab/w3"));
                    //focusBall = GameObject.CreatePrimitive(PrimitiveType.Capsule);
                    //focusBall = new GameObject();
                    focusBall.name = "CameraFocus";
                    GameObject objRec = Resources.Load("MyProbe") as GameObject;
                    objRec = GameObject.Instantiate(objRec);
                    objRec.transform.parent = focusBall.transform;
                    objRec.transform.localPosition = new Vector3(0,50,0);
                }
                if (focusBall != null)
                {
                    focusBall.transform.position = focusPos;
                    focusBall.transform.eulerAngles = new Vector3(0, rotH + 90f, 0);
                }
            }
        }

        float rotH = 0;
        /// <summary>水平旋转角度 0~360</summary>
        public float RotH
        {
            get { return rotH; }
            set
            {
                rotH = value;
                rotH = rotH % 360f;
                needRefreshBiasPos = true;
            }
        }

        float rotV = 2;
        /// <summary>垂直旋转角度 2~88, 88度时俯视地面</summary>
        public float RotV
        {
            get { return rotV; }
            set
            {
                rotV = value;
                rotV = Mathf.Clamp(rotV, -88f, 88f);
                needRefreshBiasPos = true;
            }
        }

        /// <summary>镜头离焦点距离</summary>

        float minFocusDis = 1f;
        float maxFocusDis = float.MaxValue;

        private float focusDistance = 1f;
        public float FocusDistance
        {
            get { return focusDistance; }
            set
            {
                focusDistance = Mathf.Clamp(value, minFocusDis, maxFocusDis);
                needRefreshBiasPos = true;
            }
        }

        /// <summary>刷新镜头偏移坐标</summary>
        public void refreshBiasPos(bool immediatly = false)
        {
            if (needRefreshBiasPos || immediatly)
            {
                height = Mathf.Sin(RotV / 180 * Mathf.PI) * FocusDistance;

                radius = Mathf.Cos(RotV / 180 * Mathf.PI) * FocusDistance;
                float deltaX = radius * Mathf.Cos((180 - RotH) / 180 * Mathf.PI);
                float deltaY = radius * Mathf.Sin((180 - RotH) / 180 * Mathf.PI);
                DeltaVec.Set(deltaX, height, deltaY);
                needRefreshBiasPos = false;
            }
        }
    }

}